﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ValueGeneration;

namespace Coder.Workflow
{
    /// <summary>
    ///     进行扩展
    /// </summary>
    public class WorkflowNumberGenerator : ValueGenerator<string>
    {
        private readonly IDictionary<Type, int> _numberPools = new ConcurrentDictionary<Type, int>();

        public override bool GeneratesTemporaryValues => false;


        protected int GetLastWorkflowInstance(EntityEntry entry)
        {
            lock (this)
            {
                var now = DateTime.Today.AddDays(1);
                var last = entry.Context.Set<ProcessInstance>().OrderByDescending(f => f.CreateTime)
                    .FirstOrDefault(f => f.CreateTime < now);
                if (last != null)
                    if (!string.IsNullOrEmpty(last.Number))
                        return ToIndex(last.Number, entry);

                return 0;
            }
        }

        protected virtual int ToIndex(string number, EntityEntry entry)
        {
            return Convert.ToInt32(number.Substring(8).TrimStart('0'));
        }

        protected virtual string GeneratorNumber(int index, EntityEntry entry)
        {
            return DateTime.Today.ToString("yyyyMMdd") + index.ToString().PadLeft(5, '0');
        }

        public sealed override string Next(EntityEntry entry)
        {
            lock (this)
            {
                var number = GetLastWorkflowInstance(entry);
                if (
                    !_numberPools.ContainsKey(entry.GetType()))
                    _numberPools.Add(entry.GetType(), number);
                else
                    number = _numberPools[entry.GetType()];

                number++;
                _numberPools[entry.GetType()] = number;
                return GeneratorNumber(number, entry);
            }
        }
    }
}